﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace Xinnos.Lca.Yacht.Analyzer.View
{
    internal class AssessmentViewModel:INotifyPropertyChanged
    {
        private static AssessmentViewModel mInstance = null;
        public event PropertyChangedEventHandler PropertyChanged;
        public ObservableCollection<RateRowViewModel> Rows { get; set; }

        private AssessmentViewModel()
        {
            if (null == Rows) Rows = new ObservableCollection<RateRowViewModel>();
        }

        public void Update()
        {
            Rows.Clear();

            WorkBreakdownStructureGroupViewModel _objects = null;
            WorkBreakdownStructuresViewModel _structures = WorkBreakdownStructuresViewModel.GetInstance();
            ConfigurationViewModel _configuration = ConfigurationViewModel.GetInstance();
            List<List<WorkBreakdownStructureViewModel>> _layers = new List<List<WorkBreakdownStructureViewModel>>();
            foreach (WorkBreakdownStructureGroupViewModel _group in _structures.Groups)
            {
                if (_configuration.Object == _group.Name) _objects = _group;
                else
                {
                    List<WorkBreakdownStructureViewModel> _leaves = GetLeaves(_group.WorkBreakdownStructures);
                    if (null != _leaves) _layers.Add(_leaves);
                }
            }
            List<List<WorkBreakdownStructureViewModel>> _lists = GetSequence(_layers, 0);
            if (null != _lists)
            {
                foreach (List<WorkBreakdownStructureViewModel> _list in _lists)
                {
                    RateRowViewModel _row = new RateRowViewModel();
                    foreach (WorkBreakdownStructureViewModel _structure in _list) _row.Sequences.Add(_structure);
                    Rows.Add(_row);
                }
            }
            if (null != _objects)
            {
                List<ObjectViewModel> _transformeds = AppendObjectSequence(_objects.WorkBreakdownStructures);
                foreach (ObjectViewModel _object in _transformeds)
                {
                    IEnumerable<ObjectRateViewModel> _rates = _object.Calculate();
                    if (null == _rates)
                    {
                        foreach (RateRowViewModel _row in Rows)
                        {
                            // 값이 전혀 없는 경우 일단 0 값을 생성해 넣는 것으로 처리, 추후 식별 방법이 달라지면 아래 코드 교체
                            ObjectRateViewModel _nullable = new ObjectRateViewModel();
                            _nullable.Sequences = _row.Sequences;
                            _nullable.Rate = 0.0;
                            _row.Rates.Add(_nullable);
                        }
                    }
                    else
                    {
                        foreach (ObjectRateViewModel _rate in _rates)
                        {
                            RateRowViewModel _found = null;
                            foreach (RateRowViewModel _row in Rows)
                            {
                                if (_row.Sequences.Count == _rate.Sequences.Count)
                                {
                                    bool _matched = true;
                                    for (int i = 0; i < _row.Sequences.Count; i++)
                                    {
                                        if (_row.Sequences[i] != _rate.Sequences[i])
                                        {
                                            _matched = false;
                                            break;
                                        }
                                    }
                                    if (_matched) _found = _row;
                                }
                                if (null != _found) break;
                            }
                            _found.Rates.Add(_rate);
                        }
                    }
                }
            }
            for (int i = Rows.Count; i > 0; i--)
            {
                RateRowViewModel _row = Rows[i - 1];
                if (0 == _row.Rates.Count) Rows.Remove(_row);
            }
        }

        public static AssessmentViewModel GetInstance()
        {
            if (null == mInstance) mInstance = new AssessmentViewModel();
            mInstance.Update();
            return mInstance;
        }

        private List<List<WorkBreakdownStructureViewModel>> GetSequence(IEnumerable<List<WorkBreakdownStructureViewModel>> enumerable,int nIndex)
        {
            List<List<WorkBreakdownStructureViewModel>> _list = null;
            if (null == enumerable) return _list;
            if (enumerable.Count<List<WorkBreakdownStructureViewModel>>() > nIndex)
            {
                List<WorkBreakdownStructureViewModel> _currents = enumerable.ElementAt<List<WorkBreakdownStructureViewModel>>(nIndex);
                foreach (WorkBreakdownStructureViewModel _current in _currents)
                {
                    List<List<WorkBreakdownStructureViewModel>> _nexts = GetSequence(enumerable, nIndex + 1);
                    if (null == _list) _list = new List<List<WorkBreakdownStructureViewModel>>();
                    if (null == _nexts)
                    {
                        List<WorkBreakdownStructureViewModel> _row = new List<WorkBreakdownStructureViewModel>();
                        _row.Add(_current);
                        _list.Add(_row);
                    }
                    else
                    {
                        foreach (List<WorkBreakdownStructureViewModel> _next in _nexts)
                        {
                            List<WorkBreakdownStructureViewModel> _row = new List<WorkBreakdownStructureViewModel>();
                            _row.Add(_current);
                            _row.AddRange(_next);
                            _list.Add(_row);
                        }
                    }
                }
            }
            return _list;
        }

        private List<WorkBreakdownStructureViewModel> GetLeaves(IEnumerable<WorkBreakdownStructureViewModel> enumerable)
        {
            List<WorkBreakdownStructureViewModel> _leaves = null;
            if (null == enumerable) return _leaves;
            List<WorkBreakdownStructureViewModel> _currents = null;
            foreach (WorkBreakdownStructureViewModel _structure in enumerable)
            {
                if (0 < _structure.Children.Count)
                {
                    List<WorkBreakdownStructureViewModel> _children = GetLeaves(_structure.Children);
                    if (null != _children)
                    {
                        if (null == _leaves) _leaves = new List<WorkBreakdownStructureViewModel>();
                        _leaves.AddRange(_children);
                    }
                }
                if (null == _leaves)
                {
                    if (null == _currents) _currents = new List<WorkBreakdownStructureViewModel>();
                    _currents.Add(_structure);
                }
            }
            if (null == _leaves) _leaves = _currents;
            return _leaves;
        }

        private List<ObjectViewModel> AppendObjectSequence(IEnumerable<WorkBreakdownStructureViewModel> enumerable)
        {
            List<ObjectViewModel> _list = null;
            foreach (ObjectViewModel _object in enumerable)
            {
                if (null == _list) _list = new List<ObjectViewModel>();
                _list.Add(_object);
                if (0 < _object.Children.Count)
                {
                    List<ObjectViewModel> _transformeds = new List<ObjectViewModel>();
                    foreach (WorkBreakdownStructureViewModel _child in _object.Children) _transformeds.Add(_child as ObjectViewModel);
                    List<ObjectViewModel> _children = AppendObjectSequence(_transformeds);
                    if (null != _children) _list.AddRange(_children);
                }
            }
            return _list;
        }

        private void RaisePropertyChanged(string strPropertyName)
        {
            PropertyChangedEventHandler _handler = this.PropertyChanged;
            if (null != _handler) _handler(this, new PropertyChangedEventArgs(strPropertyName));
        }
    }
}
